home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / sq_usq.arc / USQ18U.C < prev   
Text File  |  1986-05-03  |  13KB  |  426 lines

  1. static char *sccsid = "@(#)usq.c        1.8u (UCF) 83/09/02";
  2. /*
  3.  *      usq.c - CP/M compatible file unsqueezer utility
  4.  *
  5.  *      compile as follows:
  6.  *      cc [-DVAX] -O usq.c -o usq
  7.  *         (define VAX only if running on VAX)
  8.  */
  9.  
  10. /*      modified by J. Chappell 02-02-84 to check if ferror occurred on write
  11.                                 02-07-84 to accept wildcards in filenames
  12.                                 09-05-84 to give message for disk full
  13.         modified by M. Sehorne  09-10-84 to correct message output format
  14. */
  15.  
  16.  
  17. #include <stdio.h>
  18. /* #include <signal.h> */
  19. /* #include <ctype.h> */
  20.  
  21. #define TRUE 1
  22. #define FALSE 0
  23. #define ERROR (-1)
  24. #define PATHLEN 312     /* Number of characters allowed in pathname */
  25. #define OK 0
  26.  
  27. #define VERSION "1.8u   09-02-83"
  28. #define RECOGNIZE 0xFF76        /* unlikely pattern */
  29. #define DLE 0x90                /* repeat byte flag */
  30. #define SPEOF 256               /* special endfile token */
  31. #define NUMVALS 257             /* 256 data values plus SPEOF*/
  32. #define LARGE 30000
  33.  
  34. #ifdef VAX   /* then we don't want 32 bit integers */
  35.  
  36. typedef short INT;
  37. typedef unsigned short UNSIGNED;
  38.  
  39. #else   /*  16 bit machines  */
  40.  
  41. typedef int INT;
  42. typedef unsigned UNSIGNED;
  43.  
  44. #endif
  45.  
  46. struct _sqleaf {                /* Decoding tree */
  47.         INT _children[2];       /* left, right */
  48. };
  49. struct _sqleaf Dnode[NUMVALS - 1];
  50.  
  51.  
  52. INT Bpos;               /* last bit position read */
  53. INT Curin;              /* last byte value read */
  54. INT Repct;              /* Number of times to return value */
  55. INT Value;              /* current byte value or EOF */
  56.  
  57. INT MakeLCPathname=TRUE;        /* translate pathname to lc if all caps */
  58. INT Nlmode=FALSE;               /* zap cr's if true */
  59. INT Inbackground = FALSE;
  60.  
  61. INT getcr(), getuhuff(), portgetw();
  62.  
  63. extern int fflush(),ferror(),fclose();
  64. #define WILDCARD TRUE
  65. #define DOS TRUE
  66.  
  67. main(argc, argv)
  68. unsigned char *argv[];
  69. {
  70.         register unsigned char *cp;
  71.         register INT npats=0;
  72.         unsigned char **patts;
  73.         INT n, errorstat;
  74.  
  75. /*
  76.         if (signal(SIGINT, SIG_IGN)==SIG_IGN)
  77.                 Inbackground++;
  78.         else
  79.                 signal(SIGINT, SIG_DFL);
  80.         signal(SIGHUP, SIG_IGN);
  81.                                         */
  82.  
  83.         errorstat=0;
  84.         if(argc<2)
  85.                 goto usage;
  86.         while (--argc) {
  87.                 cp = *++argv;
  88.                 if(*cp == '-') {
  89.                         while( *++cp) {
  90.                                 switch(*cp) {
  91.                                 case 'n':
  92.                                         Nlmode=TRUE; break;
  93.                                 case 'u':
  94.                                         MakeLCPathname=FALSE; break;
  95.                                 default:
  96.                                         goto usage;
  97.                                 }
  98.                         }
  99.                 }
  100.                 else if( !npats && argc>0) {
  101.                         if(argv[0][0]) {
  102.                                 npats=argc;
  103.                                 patts=argv;
  104.                         }
  105.                 }
  106.         }
  107.         if(npats < 1) {
  108. usage:
  109.                 fprintf(stderr,"File squeezer version %s by\n\tRichard Greenlaw\n\t251 Colony Ct.\n\tGahanna, Ohio 43230\n", VERSION);
  110.                 fprintf(stderr,"Usage: usq [-nu] file ...\n");
  111.                 fprintf(stderr,"\t-n Nlmode: remove carriage returns\n");
  112.                 fprintf(stderr,"\t-u preserve Uppercase pathnames\n");
  113. #ifdef WILDCARD
  114.                 fprintf(stderr,"\n\tWildcards are acceptable in filenames.\n");
  115.                 fprintf(stderr," \tThis means that you can USQ *.?Q?\n");
  116. #endif
  117.                 fprintf(stderr,"\n\tUSQ will write the output file to the");
  118.                 fprintf(stderr," \n\tcurrently logged drive/directory.\n");
  119.                 exit(1);
  120.         }
  121.  
  122. #ifdef WILDCARD
  123.         for(n=0; n<npats; ++n){
  124.                 unsigned char *dir(), *cp, *s;
  125.                 if(cp=dir(patts[n],1)){
  126.                    for(s=cp;*s;s+=(strlen(s)+1)) errorstat |= squeeze(s);
  127.                    free(cp);
  128.                 }
  129.                 else errorstat |= squeeze(patts[n]);
  130.         }
  131. #else
  132.         for(n=0; n<npats; ++n)
  133.                 errorstat |= squeeze(patts[n]);
  134. #endif
  135.  
  136.         exit(errorstat != 0);
  137. }
  138.  
  139. /*
  140.         The following code is primarily from typesq.c and utr.c.  Typesq
  141. is a modification of USQ by Dick Greenlaw.  Those modifications (usq
  142. to typesq) were made by Bob Mathias, I am responsible for the butchery
  143. done to make it work with cat.
  144.  
  145. */
  146.  
  147. FILE *in, *out;
  148. squeeze(fname)
  149. unsigned char *fname;
  150. {
  151.         register INT i, c;
  152.         register unsigned char *p;
  153.         register INT numnodes;                  /* size of decoding tree */
  154.         register UNSIGNED crc;
  155.         UNSIGNED filecrc;
  156.         unsigned char origname[PATHLEN];        /* Original file name without
  157.                                                   drive */
  158.         long written;   /* number of bytes written */
  159.  
  160.         init_cr(); init_huff(); crc=0;
  161.  
  162.         if((in=fopen( fname, "rb"))==NULL) {
  163.                 fprintf(stderr, "usq: can't open %s\n", fname);
  164.                 return ERROR;
  165.         }
  166.         if(portgetw(in) != (INT) RECOGNIZE) {/* Process header */
  167.                 fprintf(stderr, "usq: %s is not a SQueezed file\n", fname);
  168.                 return(ERROR);
  169.         }
  170.         filecrc = (UNSIGNED) portgetw(in);      /* checksum */
  171.         p = origname;                           /* Get original file name */
  172.         do {                                    /* send it to array */
  173.                 *p = getc(in);
  174.         } while(*p++ != '\0');
  175.  
  176.         numnodes = portgetw(in);
  177.         if(numnodes < 0 || numnodes >= NUMVALS) {
  178.                 fprintf(stderr, "usq: %s has invalid decode tree\n", fname);
  179.                 fclose(in);
  180.                 return(ERROR);
  181.         }
  182.         /* Initialize for possible empty tree (SPEOF only) */
  183.         Dnode[0]._children[0] = -(SPEOF + 1);
  184.         Dnode[0]._children[1] = -(SPEOF + 1);
  185.  
  186.         for(i = 0; i < numnodes; ++i) { /* Get decoding tree from file */
  187.                 Dnode[i]._children[0] = portgetw(in);
  188.                 Dnode[i]._children[1] = portgetw(in);
  189.         }
  190.         /* Get translated output bytes and write file */
  191.         if(MakeLCPathname && !IsAnyLower(origname))
  192.                 uncaps(origname);
  193.         for(p=origname; *p; ++p)                /* change / to _ */
  194.                 if( *p == '/')
  195.                         *p = '_';
  196.         if (!Inbackground)
  197.                 fprintf(stderr,"usq: unsqueezing %s to %s ",fname,origname);
  198.         if((out=fopen(origname, "wb"))==NULL) {
  199.                 fprintf(stderr, "usq: can't create %s\n", origname);
  200.         }
  201.  
  202.         written=0;
  203.         while ((c = getcr()) != EOF) {
  204.                 crc += (UNSIGNED) c;
  205.                 if ( c == '\r' && Nlmode)
  206.                         continue;
  207.                 if(fputc(c,out)!=c){
  208.                         fclose(in);
  209.                         crash(origname);
  210.                 }
  211.                 else ++written;
  212.         }
  213.         fclose(in);
  214.  
  215.         if(fflush(out)<0 || ferror(out)<0 || fclose(out)<0)
  216.                 crash(origname);
  217.  
  218.         if( crc != filecrc ) {
  219.                 fprintf(stderr, "usq: bad checksum in %s\n", fname);
  220.                 fflush(stdout);
  221.                 return(ERROR);
  222.         }
  223.         fprintf(stderr,"%8ld bytes written.\n",written);
  224.         return(OK);
  225. }
  226.  
  227. crash(fn) /* crash due to error writing file */
  228. char *fn;
  229. {
  230.  
  231.   fprintf(stderr,"\nusq: Error writing file: %s\n",fn);
  232.   fprintf(stderr,"\nThe disk you are writing to is probably full.\n");
  233. #ifdef DOS
  234.   fprintf(stderr,"\nTry running CHKDSK on your destination disk.\n");
  235. #else
  236.   fprintf(stderr,"\nTry running STAT on your destination disk.\n");
  237. #endif
  238.   exit(1);
  239. }
  240.  
  241. /*** from utr.c - */
  242. /* initialize decoding functions */
  243.  
  244. init_cr()
  245. {
  246.         Repct = 0;
  247. }
  248.  
  249. init_huff()
  250. {
  251.         Bpos = 99;      /* force initial read */
  252. }
  253.  
  254. /* Get bytes with decoding - this decodes repetition,
  255.  * calls getuhuff to decode file stream into byte
  256.  * level code with only repetition encoding.
  257.  *
  258.  * The code is simple passing through of bytes except
  259.  * that DLE is encoded as DLE-zero and other values
  260.  * repeated more than twice are encoded as value-DLE-count.
  261.  */
  262.  
  263. INT
  264. getcr()
  265. {
  266.         register INT c;
  267.  
  268.         if(Repct > 0) {
  269.                 /* Expanding a repeated char */
  270.                 --Repct;
  271.                 return(Value);
  272.         } else {
  273.                 /* Nothing unusual */
  274.                 if((c = getuhuff()) != DLE) {
  275.                         /* It's not the special delimiter */
  276.                         Value = c;
  277.                         if(Value == EOF)
  278.                                 Repct = LARGE;
  279.                         return(Value);
  280.                 } else {
  281.                         /* Special token */
  282.                         if((Repct = getuhuff()) == 0)
  283.                                 /* DLE, zero represents DLE */
  284.                                 return(DLE);
  285.                         else {
  286.                                 /* Begin expanding repetition */
  287.                                 Repct -= 2;     /* 2nd time */
  288.                                 return(Value);
  289.                         }
  290.                 }
  291.         }
  292. }
  293. /* Decode file stream into a byte level code with only
  294.  * repetition encoding remaining.
  295.  */
  296.  
  297. INT
  298. getuhuff()
  299. {
  300.         register INT i;
  301.  
  302.         /* Follow bit stream in tree to a leaf*/
  303.         i = 0;  /* Start at root of tree */
  304.         do {
  305.                 if(++Bpos > 7) {
  306.                         if((Curin = getc(in)) == ERROR)
  307.                                 return(ERROR);
  308.                         Bpos = 0;
  309.                         /* move a level deeper in tree */
  310.                         i = Dnode[i]._children[1 & Curin];
  311.                 } else
  312.                         i = Dnode[i]._children[1 & (Curin >>= 1)];
  313.         } while(i >= 0);
  314.  
  315.         /* Decode fake node index to original data value */
  316.         i = -(i + 1);
  317.         /* Decode special endfile token to normal EOF */
  318.         i = (i == SPEOF) ? EOF : i;
  319.         return(i);
  320. }
  321. /*
  322.  * Machine independent getw which always gets bytes in the same order
  323.  *  as the CP/M version of SQ wrote them
  324.  */
  325. INT
  326. portgetw(f)
  327. FILE *f;
  328. {
  329.         register INT c;
  330.  
  331.         c = getc(f) & 0377;
  332.         return(c | (getc(f) << 8));
  333. }
  334.  
  335.  
  336. /* make string s lower case */
  337. uncaps(s)
  338. unsigned char *s;
  339. {
  340.         for( ; *s; ++s)
  341.                 if(isupper(*s))
  342.                         *s = tolower(*s);
  343. }
  344.  
  345.  
  346. /*
  347.  * IsAnyLower returns TRUE if string s has lower case letters.
  348.  */
  349. IsAnyLower(s)
  350. unsigned char *s;
  351. {
  352.         for( ; *s; ++s)
  353.                 if (islower(*s))
  354.                         return(TRUE);
  355.         return(FALSE);
  356. }
  357.  
  358.  
  359. #ifdef WILDCARD
  360. /*      dir: for DOS ALL
  361.  
  362.         Entry:
  363.                 1. Filename possibly containing wildcards ? and *
  364.                 2. Drive specifier flag
  365.  
  366.         Returns: Pointer to data area containing NULL terminated
  367.                  list of filenames, or NULL if none found.
  368.  
  369.         Notes: User must free up data allocated by this function
  370.                 with free() if memory is to be restored to heap
  371.                 after use.
  372.  
  373.               Drive specifier: if non-zero will drive specifiers
  374.                 will be put on file names
  375.  
  376.               Path names: not supported
  377.  
  378. */
  379.  
  380. unsigned char *dir(filespec,drflag)
  381. unsigned char *filespec;
  382. short drflag;
  383. {
  384. #define BLOCK 100               /* room for fcb,dta,etc.. */
  385. #define FIRST 0x1100            /* search first */
  386. #define NEXT 0x1200             /* search next */
  387. #define CURRENT 0x19            /* get current drive */
  388. #define PARSE 0x2900            /* parse file name */
  389. #define SETDTA 0x1a00           /* set disk transfer address */
  390.  
  391. unsigned char *fcb,*rets,*cp,*tmp,*dta,*realloc();
  392. unsigned short mode,pos,i;
  393. struct regval { int ax,bx,cx,dx,si,di,ds,es;} r;
  394.  
  395.   tmp=realloc(0,BLOCK); fcb=realloc(0,BLOCK);
  396.   dta=realloc(0,BLOCK); rets=realloc(0,BLOCK);
  397.  
  398.   segread(&r.si);                       /* parse file name */
  399.   r.es=r.ds; r.si=filespec; r.di=fcb; r.ax=PARSE; sysint21(&r,&r);
  400.  
  401.   segread(&r.si);                       /* set dta */
  402.   r.dx=dta; r.ax=SETDTA; sysint21(&r,&r);
  403.  
  404.   for(pos=0,mode=FIRST;;mode=NEXT){
  405.         segread(&r.si); r.ax=mode; r.dx=fcb; sysint21(&r,&r);   /* search  */
  406.         if(r.ax&0xff==0xff)break;                       /* not found */
  407.         cp=tmp;
  408.         if(drflag){                             /* put on drive specifier */
  409.                 if(*dta==0)*dta=(bdos(CURRENT)&0xff)+1;
  410.                 *cp++=*dta+'A'-1; *cp++=':';
  411.         }
  412.         for(i=1;i<9;i++)if(*(dta+i)!=' ')*cp++=*(dta+i); *cp++='.';
  413.         for(;i<12;i++)if(*(dta+i)!=' ')*cp++=*(dta+i); *cp='\0';
  414.         rets=realloc(rets,pos+strlen(tmp)+1);   /* store file name */
  415.         strcpy(rets+pos,tmp);
  416.         pos+=(strlen(tmp)+1);
  417.   }
  418.  
  419.   if(pos)rets=realloc(rets,pos+strlen(tmp)+1);
  420.   else free(rets);
  421.   free(fcb); free(tmp); free(dta);
  422.   return pos ? rets: 0;
  423. }
  424.  
  425. #endif
  426.